home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 February
/
EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso
/
earcd
/
util4
/
cliphn12.lha
/
Src
/
clip-handler.c
Wrap
C/C++ Source or Header
|
1995-11-21
|
14KB
|
492 lines
/*
** clip-handler.c
** DOS handler for Clipboard access
** Copyright © 1995 Michael Letowski
*/
#define __USE_SYSBASE
#include <exec/types.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/filehandler.h>
#include <libraries/iffparse.h>
#include <devices/clipboard.h>
#include <support/types.h>
#include <support/exec.h>
#include <support/dos.h>
#include <string.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/iffparse.h>
#include "clip-handler.rev.h"
/****** clip-handler/clip_handler() *****************************************
*
* NAME
* clip_handler -- a handler for clipboard access. (V37)
*
* SYNOPSIS
* Open("CLIP:[unit_num]");
*
* FUNCTION
* Clip-handler allows AmigaDOS to interface to a standard clipboard
* device. Clip-handler takes data from an application, packs it into
* FTXT CHRS format and stores in clipboard. Or it takes data FTXT CHRS
* data from the clipboard and passes it into an application.
*
* INPUTS
* unit_num - clipboard.device unit number. Must be in 0-255 range.
* Default values is PRIMARY_CLIP.
*
* PACKETS
* ACTION_FINDINPUT
* ACTION_FINDOUTPUT
* ACTION_READ
* ACTION_WRITE
* ACTION_END
* ACTION_DIE
* ACTION_IS_FILESYSTEM
*
* MOUNTLIST ENTRIES
* This is default mountlist entry used for clip-handler:
*
* CLIP: Handler = L:clip-handler
* Priority = 5
* StackSize = 4096
* GlobVec = -1
* #
*
* NOTES
* At present only FTXT CHRS chunks are recognized and utilized.
*
* EXAMPLES
* Store Startup-Sequence in default clipboard unit:
* Copy S:Startup-Sequence CLIP:
*
* Get directory's listing and place it in clipboard unit 1:
* List >CLIP:1
*
* View clipboard's contents
* Type CLIP:
*
* BUGS
* Accessing CLIP: for reading and writing at the same time will hang
* clip-handler.
* Neither appending data (ACTION_FINDUPDATE) nor seeking (ACTION_SEEK)
* is supported yet.
*
* SEE ALSO
* clipboard.device, iffparse.library.
*
*****************************************************************************
*
*/
/*
** Constants
*/
#define DOS_NAME "dos.library"
#define DOS_VERN 37L
#define IFFP_NAME "iffparse.library"
#define IFFP_VERN 37L
#define ID_FTXT MAKE_ID('F','T','X','T')
#define ID_CHRS MAKE_ID('C','H','R','S')
#define PATH_SIZE 256
/*
** Macros
*/
#define SetPktRes(pkt,res1,res2) ((pkt)->dp_Res1=(res1),(pkt)->dp_Res2=(res2))
/*
** Globals
*/
STATIC CONST TEXT VersionString[]=
VERSION(PROG_NAME,PROG_VERSION,PROG_REVISION,PROG_DATE);
/* Library bases */
struct ExecBase *SysBase;
struct DosLibrary *DOSBase;
struct Library *IFFParseBase;
/*
** Private prototypes
*/
/* Packet routines */
STATIC struct DosPacket *WaitPacket(struct MsgPort *port);
STATIC VOID ReplyPacket(struct DosPacket *packet, struct MsgPort *port);
STATIC VOID ReplyPacketRes(struct DosPacket *packet, struct MsgPort *port,
LONG res1, LONG res2);
STATIC VOID FlushPackets(struct MsgPort *port);
/* clip-handler routines */
STATIC struct IFFHandle *OpenCH(struct DosPacket *packet);
STATIC VOID CloseCH(struct IFFHandle *iff);
STATIC LONG OpenInputCH(struct DosPacket *packet);
STATIC LONG OpenOutputCH(struct DosPacket *packet);
#ifdef DO_SEEK
STATIC LONG OpenUpdateCH(struct DosPacket *packet);
#endif
STATIC LONG CloseIOUCH(struct DosPacket *packet);
STATIC VOID ReadClipboard(struct DosPacket *packet);
STATIC VOID WriteClipboard(struct DosPacket *packet);
#ifdef DO_SEEK
STATIC VOID SeekClipboard(struct DosPacket *packet);
#endif
STATIC LONG IFF2DOS(LONG iffError);
/*
** Public functions
*/
SAVEDS LONG ClipHandler(VOID)
{
struct Library *LocalDOSBase;
struct Library *LocalIFFParseBase;
struct Process *PR;
struct MsgPort *MP,*PacketPort;
struct DosPacket *Pkt;
struct DeviceNode *DevNode;
LBOOL Done=FALSE;
ULONG OpenCount=0;
SysBase=INITSYSBASE; /* Set up SysBase */
PR=ThisProcessS;
MP=&PR->pr_MsgPort;
if(PR->pr_CLI) /* Run from shell? */
return(RETURN_FAIL); /* Failure */
Pkt=WaitPacket(MP); /* Get startup message */
try(DevNode=(struct DeviceNode *)BADDR(Pkt->dp_Arg3),NO_DEV);
/* Open libraries */
unless(LocalDOSBase=OpenLibrary(DOS_NAME,DOS_VERN))
throw2(ReplyPacketRes(Pkt,MP,DOSFALSE,ERROR_INVALID_RESIDENT_LIBRARY), NO_DOS);
unless(LocalIFFParseBase=OpenLibrary(IFFP_NAME,IFFP_VERN))
throw2(ReplyPacketRes(Pkt,MP,DOSFALSE,ERROR_INVALID_RESIDENT_LIBRARY), NO_IFFP);
/* Create port */
unless(PacketPort=CreateMsgPort())
throw2(ReplyPacketRes(Pkt,MP,DOSFALSE,ERROR_NO_FREE_STORE), NO_PORT);
/* Set up global bases */
DOSBase=(struct DosLibrary *)LocalDOSBase; /* Set up global bases */
IFFParseBase=LocalIFFParseBase;
DevNode->dn_Task=PacketPort;
Pkt->dp_Arg4=(LONG)PacketPort;
ReplyPacketRes(Pkt,PacketPort,DOSTRUE,Pkt->dp_Res2);
while(!Done)
{
Pkt=WaitPacket(PacketPort);
switch(Pkt->dp_Type)
{
case ACTION_FINDINPUT: /* (handle,lock,name) -> success */
OpenCount+=OpenInputCH(Pkt);
break;
case ACTION_FINDOUTPUT: /* (handle,lock,name) -> success */
OpenCount+=OpenOutputCH(Pkt);
break;
#ifdef DO_SEEK
case ACTION_FINDUPDATE: /* (handle,lock,name) -> success */
OpenCount+=OpenUpdateCH(Pkt);
break;
#endif
case ACTION_END: /* (handle) -> success */
OpenCount-=CloseIOUCH(Pkt);
break;
case ACTION_READ: /* (handle,buffer,len) -> cnt */
ReadClipboard(Pkt);
break;
case ACTION_WRITE: /* (handle,buffer,len) -> cnt */
WriteClipboard(Pkt);
break;
#ifdef DO_SEEK
case ACTION_SEEK:
SeekClipboard(Pkt);
break;
#endif
case ACTION_DIE:
if(OpenCount)
SetPktRes(Pkt,DOSFALSE,ERROR_OBJECT_IN_USE);
else
{
SetPktRes(Pkt,DOSTRUE,0);
Done=TRUE;
}
break;
case ACTION_IS_FILESYSTEM:
SetPktRes(Pkt,DOSFALSE,0);
break;
default:
SetPktRes(Pkt,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
break;
}
ReplyPacket(Pkt,PacketPort);
}
Forbid(); /* Disable task switching */
DevNode->dn_Task=NULL; /* Switch off device */
FlushPackets(PacketPort); /* Discard waiting packets */
UnLoadSeg(DevNode->dn_SegList); /* Unload code */
DevNode->dn_SegList=NULL; /* And mark this fact */
Permit(); /* Enable task switching */
catch(NO_PORT, DeleteMsgPort(PacketPort));
catch(NO_IFFP, CloseLibrary(LocalIFFParseBase));
catch(NO_DOS, CloseLibrary(LocalDOSBase));
catch(NO_DEV, );
return(0);
} /* ClipHandler */
/*
** Private functions
*/
STATIC struct DosPacket *WaitPacket(struct MsgPort *port)
{
WaitPort(port);
return((struct DosPacket *)GetMsg(port)->mn_Node.ln_Name);
} /* WaitPacket */
STATIC VOID ReplyPacket(struct DosPacket *packet, struct MsgPort *port)
{
struct MsgPort *ReplyPort=packet->dp_Port;
packet->dp_Port=port;
packet->dp_Link->mn_Node.ln_Name=(STRPTR)packet;
PutMsg(ReplyPort,packet->dp_Link);
} /* ReplyPacket */
STATIC VOID ReplyPacketRes(struct DosPacket *packet, struct MsgPort *port,
LONG res1, LONG res2)
{
SetPktRes(packet,res1,res2);
ReplyPacket(packet,port);
} /* ReplyPacketRes */
STATIC VOID FlushPackets(struct MsgPort *port)
{
struct DosPacket *Packet;
while(Packet=(struct DosPacket *)GetMsg(port)->mn_Node.ln_Name)
ReplyPacketRes(Packet,port,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
} /* FlushPackets */
STATIC struct IFFHandle *OpenCH(struct DosPacket *packet)
{
CHAR Name[PATH_SIZE];
STRPTR Str=(STRPTR)BADDR(packet->dp_Arg3);
struct FileHandle *Handle=FH(packet->dp_Arg1);
struct IFFHandle *IFF;
LONG Unit;
SetPktRes(packet,DOSFALSE,0);
Handle->fh_Arg1=0;
Handle->fh_Port=NULL; /* Non-interactive file */
memcpy(Name,&Str[1],Str[0]); /* Copy data */
Name[Str[0]]='\0'; /* NULL-terminate */
Str=Name;
if(Str=strchr(Str,':')) /* Device name given */
Str++; /* Skip the colon */
StrToLong(Str,&Unit); /* <Unit> gets set to 0 in case of error */
unless(IFF=AllocIFF())
throw2(packet->dp_Res2=ERROR_NO_FREE_STORE, NO_IFF);
unless(IFF->iff_Stream=(ULONG)OpenClipboard(Unit))
throw2(packet->dp_Res2=ERROR_NO_FREE_STORE, NO_CLIPBOARD); /* FIX: error */
InitIFFasClip(IFF);
Handle->fh_Arg1=(LONG)IFF;
packet->dp_Res1=DOSTRUE;
return(IFF);
/* Exceptions */
catch(FOO, );
catch(NO_CLIPBOARD, CloseClipboard((struct ClipboardHandle *)IFF->iff_Stream));
catch(NO_IFF, FreeIFF(IFF));
return(NULL);
} /* OpenCH */
STATIC VOID CloseCH(struct IFFHandle *iff)
{
CloseClipboard((struct ClipboardHandle *)iff->iff_Stream);
FreeIFF(iff);
} /* CloseCH */
STATIC LONG OpenInputCH(struct DosPacket *packet)
{
struct IFFHandle *IFF;
struct ContextNode *CN;
LONG Error;
try(IFF=OpenCH(packet), NO_HANDLE);
try(!(Error=OpenIFF(IFF,IFFF_READ)), NO_IFF);
try(!(Error=StopChunk(IFF,ID_FTXT,ID_CHRS)), IFF_ERROR);
try(!(Error=ParseIFF(IFF,IFFPARSE_SCAN)), IFF_ERROR);
try(CN=CurrentChunk(IFF), IFF_ERROR);
try(CN->cn_Type==ID_FTXT && CN->cn_ID==ID_CHRS, IFF_ERROR);
return(1); /* Open succesfull */
catch(IFF_ERROR, );
catch(NO_IFF, CloseIFF(IFF));
SetPktRes(packet,DOSFALSE,IFF2DOS(Error)); /* Set result */
catch(NO_HANDLE, CloseCH(IFF));
return(0); /* Open failed */
} /* OpenInputCH */
STATIC LONG OpenOutputCH(struct DosPacket *packet)
{
struct IFFHandle *IFF;
LONG Error;
try(IFF=OpenCH(packet), NO_HANDLE);
try(!(Error=OpenIFF(IFF,IFFF_WRITE)), NO_IFF);
try(!(Error=PushChunk(IFF,ID_FTXT,ID_FORM,IFFSIZE_UNKNOWN)), IFF_ERROR);
try(!(Error=PushChunk(IFF,0,ID_CHRS,IFFSIZE_UNKNOWN)), IFF_ERROR);
return(1); /* Open succesfull */
catch(IFF_ERROR, );
catch(NO_IFF, CloseIFF(IFF));
SetPktRes(packet,DOSFALSE,IFF2DOS(Error)); /* Set result */
catch(NO_HANDLE, CloseCH(IFF));
return(0); /* Open failed */
} /* OpenOutputCH */
#ifdef DO_SEEK
STATIC LONG OpenUpdateCH(struct DosPacket *packet)
{
struct IFFHandle *IFF;
LONG Error;
try(IFF=OpenCH(packet), NO_HANDLE);
try(!(Error=OpenIFF(IFF,IFFF_WRITE)), NO_IFF);
try(!(Error=StopChunk(IFF,ID_FTXT,ID_CHRS)), IFF_ERROR);
/* FIX: Should use write mode here */
try(!(Error=ParseIFF(IFF,IFFPARSE_SCAN)), IFF_ERROR);
return(1); /* Open succesfull */
catch(IFF_ERROR, );
catch(NO_IFF, CloseIFF(IFF));
SetPktRes(packet,DOSFALSE,IFF2DOS(Error)); /* Set result */
catch(NO_HANDLE, CloseCH(IFF));
return(0); /* Open failed */
} /* OpenUpdateCH */
#endif
STATIC LONG CloseIOUCH(struct DosPacket *packet)
{
struct IFFHandle *IFF=(struct IFFHandle *)packet->dp_Arg1;
#if 0
/* FIX:??? Check PopChunk() for errors */
if(ftst(IFF->iff_Flags,IFFF_WRITE)) /* Write mode */
if(PopChunk(IFF)==0) /* Close CHRS */
PopChunk(IFF); /* Close FTXT */
#endif
CloseIFF(IFF);
CloseCH(IFF);
SetPktRes(packet,DOSTRUE,0); /* Set result */
return(1);
} /* CloseIOUCH */
STATIC VOID ReadClipboard(struct DosPacket *packet)
{
struct IFFHandle *IFF=(struct IFFHandle *)packet->dp_Arg1;
STRPTR Buffer=(STRPTR)packet->dp_Arg2;
LONG ReadCnt,Bytes=packet->dp_Arg3;
SetPktRes(packet,-1,0); /* Set result */
ReadCnt=ReadChunkBytes(IFF,Buffer,Bytes); /* Read into buffer */
if(ReadCnt<0) packet->dp_Res2=IFF2DOS(ReadCnt);
else packet->dp_Res1=ReadCnt;
} /* ReadClipboard */
STATIC VOID WriteClipboard(struct DosPacket *packet)
{
struct IFFHandle *IFF=(struct IFFHandle *)packet->dp_Arg1;
STRPTR Buffer=(STRPTR)packet->dp_Arg2;
LONG WriteCnt,Bytes=packet->dp_Arg3;
SetPktRes(packet,-1,0); /* Set result */
WriteCnt=WriteChunkBytes(IFF,Buffer,Bytes); /* Write buffer */
if(WriteCnt<0) packet->dp_Res2=IFF2DOS(WriteCnt);
else packet->dp_Res1=WriteCnt;
} /* WriteClipboard */
#ifdef DO_SEEK
STATIC VOID SeekClipboard(struct DosPacket *packet)
{
struct IFFHandle *IFF=(struct IFFHandle *)packet->dp_Arg1;
struct ContextNode *CN;
LONG Offset=packet->dp_Arg2,OffsetType=packet->dp_Arg3;
LONG OldPos,NewPos=-1;
SetPktRes(packet,-1,ERROR_SEEK_ERROR); /* Set result */
unless(CN=CurrentChunk(IFF))
return;
unless(CN->cn_Type==ID_FTXT && CN->cn_ID==ID_CHRS)
return;
switch(OffsetType)
{
case OFFSET_BEGINNING: NewPos=Offset; break;
case OFFSET_CURRENT: NewPos=CN->cn_Scan+Offset; break;
case OFFSET_END: NewPos=CN->cn_Size-Offset; break;
default: break;
}
if(NewPos>0 && NewPos<CN->cn_Size) /* Can seek */
{
OldPos=CN->cn_Scan;
CN->cn_Scan=NewPos;
SetPktRes(packet,OldPos,0);
}
} /* SeekClipboard */
#endif
STATIC LONG IFF2DOS(LONG iffError)
{
LONG DOSError=ThisProcessS->pr_Result2;
unless(DOSError) /* Error not set */
switch(iffError)
{
case IFFERR_NOTIFF: DOSError=ERROR_OBJECT_NOT_FOUND; break;
case IFFERR_NOMEM: DOSError=ERROR_NO_FREE_STORE; break;
case IFFERR_SEEK: DOSError=ERROR_SEEK_ERROR; break;
case IFFERR_NOHOOK: DOSError=ERROR_NOT_IMPLEMENTED; break;
default: DOSError=ERROR_OBJECT_WRONG_TYPE; break;
}
return(DOSError);
} /* IFF2DOS */
#if 0
STATIC LONG SeekChunk(struct IFFHandle *iff, LONG offset)
{
struct IFFStreamCmd Cmd=
{
IFFCMD_SEEK, NULL, offset
}; /* Cmd */
return(CallHookPkt((struct Hook *)(iff+1),iff,&Cmd));
} /* SeekChunk */
#endif